/* 
 * File:   Factory.cpp
 * Author: Bram
 * 
 * Created on January 21, 2013, 6:30 PM
 */

#include "Factory.h"
#include "InfoCommand.h"
#include "ErrorCommand.h"
#include "DirCommand.h"
#include "PutCommand.h"
#include "RenCommand.h"
#include "SendReceiveCommand.h"
#include "SyncCommand.h"

Factory::Factory() {
}

Factory::Factory(const Factory& orig) {
}

Factory::~Factory() {
}

void Factory::assign(const char* szID, Command* pNode) {
    CommandMap &cMap = getMap();
    string dasID = szID;
    Utility::getInstance()->toUpper(dasID);
    cMap[dasID.c_str()] = pNode;
}

Command* Factory::create(string component) {
    CommandMap &cMap = getMap();
    CommandMap::iterator iFind = cMap.find(component);

    if (iFind == cMap.end()) {
        return 0;
    } else {
        return iFind->second->createNew();
    }
}

Command* Factory::extractCommand(string& input)
{
    Command* command = NULL;
    if(Utility::getInstance()->startsWith(input,"<?xml") || Utility::getInstance()->startsWith(input,"<?XML"))
    {
        command = extractCommandFromXml(input);
    }
    else
    {
        command = extractCommandFromUserInput(input);
    }
    return command;
}


Command* Factory::extractCommandFromUserInput(string& input)
{
    string commandstr;
    Command* command = NULL;
    if (input.length() > 4)// look for command with parameters
    {
        int pos = input.find(":");
        if (pos != string::npos) {
            commandstr = input.substr(0,pos);
        }
    }
    else// command without parameters
    {
        commandstr = input;
    }
    Utility::getInstance()->toUpper(commandstr);
    command = create(commandstr);
    if(command != 0){
        command->setSender("CLIENT");
        command->setType("START");
    }
    return command;
}


Command* Factory::extractCommandFromXml(string& xml)
{
    
    pugi::xml_document currXMLdoc;
    
    Command* command = NULL;
    //checkt of het wel valide xml is
    if (currXMLdoc.load(xml.c_str()))
    {
        pugi::xml_node currCommand = currXMLdoc.child("Command");
        
        //parst naar het juiste command
       command = create(currCommand.attribute("Name").value());
        
        command->setSender(currCommand.attribute("Sender").value());
        command->setType(currCommand.attribute("Type").value());
    }
    return command;
}

Command* Factory::createFromInput(string& input)
{
    
}

Command* Factory::createFromUserInput(string& input)
{
    Command* command = extractCommand(input);
    
    if(command != 0){
        int counter = 0;
        int lastPos = 0;
        int currPos = 0;

        currPos = input.find_first_of('"');
        while(currPos != string::npos)
        {
            counter++;
            if(counter == 2)
            {
                counter = 0;
                string dasParam = input.substr(lastPos+1,currPos - lastPos - 1);
                command->addParameter(input.substr(lastPos+1,currPos - lastPos - 1));
            }
            lastPos = currPos;
            currPos = input.find_first_of('"', lastPos+1);
        }
    }
    return command;
}

Command* Factory::createFromXml(string& xml)
{
    Command* command = extractCommand(xml);
    
    pugi::xml_document currXMLdoc;
    stringstream ssERROR;
    
    //checkt of het wel valide xml is
    if (currXMLdoc.load(xml.c_str()))
    {
        pugi::xml_node currCommand = currXMLdoc.child("Command");
        
        pugi::xml_node currCommandParameters = currCommand.child("Parameters");
        
        //parst de parameters en shit
        for (pugi::xml_node_iterator parametersValues = currCommandParameters.begin(); parametersValues != currCommandParameters.end(); ++parametersValues)
        {
            for (pugi::xml_node_iterator parametersValuesREAL = parametersValues->begin(); parametersValuesREAL != parametersValues->end(); ++parametersValuesREAL)
            {
                string param = parametersValuesREAL->value();
                command->addParameter(param);
            }
        }

        if(command->isValid()){
            return command;
        }
    } else {
        ssERROR.str("");
        ssERROR.clear();
        ssERROR << "ERROR - 3003 - XML COMMAND: '" << xml << "' NOT VALID!";
        return ErrorCommand::initializeWithErrorMessage(ssERROR.str());
    }
    return 0;
}

bool Factory::exists(string component) {

    CommandMap &cMap = getMap();
    CommandMap::iterator iFind = cMap.find(component);

    if (iFind == cMap.end()) {
        return false;
    } else {
        return true;
    }
}

Factory::CommandMap& Factory::getMap() {
    static CommandMap cMap;
    return cMap;
}
